package com.gulimall.search.thread;

import java.util.concurrent.*;

/**
 * @author kkk
 * @date 2022/7/28
 */
public class ThreadTest {
    //创建固定线程池
    private static ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        CompletableFuture.runAsync(() -> {
//            System.out.println("当前线程 " + Thread.currentThread().getId());
//        }, executorService);

//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getId());
//            int a = 10 / 0;
//            return new Random().nextInt();
//        }, executorService).whenComplete((res, exception) -> {
//            System.out.println("异步成功执行了 ，结果是 " + res + "  异常是 " + exception);
//        }).exceptionally(e -> {
//            System.out.println("接受到异常，同时可以返回默认值");
//            return 10;
//        });
//
//        System.out.println(future.get());

        /**
         * 方法执行完成后的处理
         */
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getId());
//            return new Random().nextInt(100);
//        }, executorService).handle((res, e) -> {
//            if (res != null) {
//                return res * 2;
//            }
//            if (e != null) {
//                return 0;
//            }
//            return 0;
//        });
//        System.out.println(future.get());

        /**
         * 线程串行化
         * 1. thenRun，不能获取到上一步结果，无返回值
         * 2. thenAcceptAsync ,可以获得上一步结果， 无返回值
         * 3. thenApplyAsync  , 可以获得上一步结果，有返回值
         */
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("执行了方法一");
//            return new Random().nextInt(100);
//        }, executorService).thenApplyAsync((res) -> {
//            System.out.println("执行了方法二");
//            System.out.println("上一步的返回值" + res);
//            return 20;
//        });
//        System.out.println(future);

        /**
         * 两任务组合
         * 1.runAfterBothAsync 等到其他两个线程完成后, 在执行，不能获取到上一步结果，无返回值
         * 2.thenAcceptBothAsync  获取到上一步结果  无返回值
         * 3.thenCombineAsync  获取到上一步结果  有返回值
         */
        CompletableFuture<String> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1 " + Thread.currentThread().getId());
            return "hello -== 1";
        }, executorService);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("任务2 " + Thread.currentThread().getId());
            return "hello -== 2";
        }, executorService);

//        future01.runAfterBothAsync(future02, () -> {
//            System.out.println("任务3 ...");
//        }, executorService);
//        future01.thenAcceptBothAsync(future02, (f1, f2) -> {
//            System.out.println("任务三 f1 => " + f1 + ", f2 => " + f2);
//        }, executorService);
//        CompletableFuture<String> future03 = future01.thenCombineAsync(future02, (f1, f2) -> {
//            System.out.println("任务三 f1 => " + f1 + ", f2 => " + f2);
//            return "hello -== 3";
//        }, executorService);
//        System.out.println(future03.get());

        /**
         * 两个任务完成一个
         * 1.runAfterEitherAsync 等到其他两个线程中一个完成后, 在执行，不能获取到上一步结果，无返回值
         * 2.acceptEither  获取到上一步结果  无返回值
         * 3.thenCombineAsync  获取到上一步结果  有返回值
         */
//        future01.runAfterEitherAsync(future02, () -> {
//            System.out.println("任务3");
//        });
//        future01.acceptEither(future02, (res) -> {
//            System.out.println("任务3 res == " + res);
//        });
//        future01.applyToEitherAsync(future02, (res) -> {
//            return "hello -== 3";
//        }, executorService);

        CompletableFuture<Void> futureImg = CompletableFuture.runAsync(() -> {
            System.out.println("图片");
        }, executorService);
        CompletableFuture<Void> futureAttr = CompletableFuture.runAsync(() -> {
            System.out.println("属性");
        }, executorService);
        CompletableFuture<Void> futureBrand = CompletableFuture.runAsync(() -> {
            System.out.println("商品");
        }, executorService);

        CompletableFuture<Void> future = CompletableFuture.allOf(futureImg, futureAttr, futureBrand);
        future.get();

    }

    public void createThreadpool() {
        /**
         * 创建线程方式
         *  1. Thread
         *  2. Runnable
         *  3. callable
         *  4.线程池
         */


        /**
         * 使用线程池创建线程
         *  1. 核心数量  线程创建好以后就立即执行
         *  2. 最大线程数量
         *  3. 存活时间 ，  当前线程大于核心线程的数量。 当线程空闲大于指定的存活时间就回收
         *  4.时间单位
         *  5.阻塞队列，当前任务大于核心线程数量，多余的任务放到阻塞队列中，空闲线程会自动到阻塞队列中自动获取
         *  6. 线程创建的工厂
         *  7.拒绝任务，线程数量大于阻塞独列，会根据对应策略 拒绝任务
         */
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 200, 10, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100000), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        /**
         * 工作顺序
         * 1. 线程池创建，准备好核心数量的核心线程，准备接受任务
         * 2. 核心线程满了，就将再进来的任务放入阻塞队列中，空闲的核心线程会自己去阻塞队列中自动获取任务执行
         * 3.阻塞队列满了，就直接开新线程执行，最大只能开到最大核心的数量
         * 4. 最大线程满了，就启用拒绝任务
         5.除了核心线程的其他线程，空闲时间超过存活时间以后，就会自动释放这些线程
         */

    }

}
